/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.compomics.dataprovider.control.logic.fasta;

import com.compomics.dataprovider.control.QueryType;
import com.compomics.dataprovider.control.logic.ConnectionManager;
import com.compomics.dataprovider.model.fasta.FastaStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Kenneth Verheggen
 */
public class UniprotFastaProvider {

    private static final org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger.getLogger(UniprotFastaProvider.class);

    //INPUT METHODS--------------------------------------------------------------------------------------------------
    private static String getFastaQuery(String taxonomyID, boolean reviewedOnly) throws MalformedURLException {
        String query = taxonomyID + "&format=fasta";
        if (reviewedOnly) {
            query = query.replace(taxonomyID, taxonomyID + "+AND+reviewed=yes");
        }
        return query;
    }

    private static String getFastaQuery(String organism, String taxonomyID, boolean reviewedOnly) throws MalformedURLException {
        //     String query = "organism="+organism.replace(" ", "+") + "+[" + taxonomyID + "]&sort=score&format=fasta";
        String query = "organism%3A" + organism.replace(" ", "+") + "+[" + taxonomyID + "]&sort=score&format=fasta";
        if (reviewedOnly) {
            query = query+"&reviewed=yes";
        }
        return query;
    }

//DOWNLOAD METHODS--------------------------------------------------------------------------------------------------
    /**
     *
     * @param stream the fastastream where the downloaded fastas should be
     * appended to
     * @param organism the name of the organism
     * @param taxonomyID the taxonomyID for the species
     * @param reviewedOnly state to indicate if only reviewed sequences should
     * be downloaded
     * @return
     * @throws IOException
     * @throws java.net.URISyntaxException
     */
    public static FastaStream downloadFastaToStream(FastaStream stream, String organism, String taxonomyID, boolean reviewedOnly) throws IOException, URISyntaxException {
        return stream.concatenate(ConnectionManager.getQueryConnection(getFastaQuery(organism, taxonomyID, reviewedOnly), QueryType.FASTA));
    }

    /**
     *
     * @param stream the fastastream where the downloaded fastas should be
     * appended to
     * @param taxonomyID the taxonomyID for the species
     * @param reviewedOnly state to indicate if only reviewed sequences should
     * be downloaded
     * @return
     * @throws IOException
     * @throws java.net.URISyntaxException
     */
    public static FastaStream downloadFastaToStream(FastaStream stream, String taxonomyID, boolean reviewedOnly) throws IOException, URISyntaxException {
        return stream.concatenate(ConnectionManager.getQueryConnection(getFastaQuery(taxonomyID, reviewedOnly), QueryType.FASTA));
    }

    /**
     *
     * @param taxonomyID the taxonomyID for the species
     * @param fastaFile the target file to save the fasta to
     * @param reviewedOnly state to indicate if only reviewed sequences should
     * be downloaded
     * @param decoy appends decoys to the current fasta (for the input)
     * @throws IOException
     * @throws java.net.URISyntaxException
     */
    public static void downloadFastaToFile(String taxonomyID, File fastaFile, boolean reviewedOnly, boolean decoy) throws IOException, URISyntaxException {
        LOGGER.debug("Downloading fasta for " + taxonomyID);
        FastaStream stream = new FastaStream(FastaSourceConverter.convertToStream(ConnectionManager.getQueryConnection(getFastaQuery(taxonomyID, reviewedOnly), QueryType.FASTA)));
        LOGGER.debug("Saving fasta to " + fastaFile.getAbsolutePath());
        stream.save(fastaFile, decoy);
        LOGGER.debug("Done");
    }

    /**
     *
     * @param taxonomyIDs list of taxonomyID for the species
     * @param fastaFile the target file to save the fasta to
     * @param reviewedOnly state to indicate if only reviewed sequences should
     * be downloaded
     * @param decoy decoy appends decoys to the current fasta (for the input)
     * @throws IOException
     * @throws java.net.URISyntaxException
     */
    public static void downloadFastasToFile(List<String> taxonomyIDs, final File fastaFile, final boolean reviewedOnly, final boolean decoy) throws IOException, URISyntaxException {
        List<ByteArrayInputStream> inputStreams = new ArrayList<>();
        for (String taxonomyID : taxonomyIDs) {
            //get streams
            LOGGER.debug("Downloading fasta for " + taxonomyID);
            inputStreams.add(FastaSourceConverter.convertToStream(ConnectionManager.getQueryConnection(getFastaQuery(taxonomyID, reviewedOnly), QueryType.FASTA)));
        }
        //use the first one for the initial object
        LOGGER.debug("Concatenating streams...");
        FastaStream stream = new FastaStream(inputStreams.get(0));
        for (int i = 1; i < inputStreams.size(); i++) {
            LOGGER.debug("Concatenating " + i + "/" + inputStreams.size());
            stream.concatenate(inputStreams.get(i));
        }
        LOGGER.debug("Saving fasta to " + fastaFile.getAbsolutePath());
        stream.save(fastaFile, true);
        LOGGER.debug("Done");
    }

    /**
     *
     * @param taxonomyID
     * @return a check whether the fasta is reachable/does exist online
     */
    public static boolean exists(String taxonomyID) {
        boolean validated = true;
        HttpURLConnection fastaURL;
        try {
            fastaURL = ConnectionManager.getQueryConnection(getFastaQuery(taxonomyID, false), QueryType.FASTA);
            if (validated) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(fastaURL.getInputStream()))) {
                    validated = (reader.readLine() != null);
                } catch (IOException ex) {
                    LOGGER.error("No online FASTA found for " + taxonomyID);
                    validated = false;
                }
            }
        } catch (MalformedURLException ex) {
            LOGGER.error("Could not contact UniProt service for " + taxonomyID);
            validated = false;
        } catch (IOException | URISyntaxException ex) {
            LOGGER.error("Could not contact UniProt service for " + taxonomyID);
            validated = false;
        }
        return validated;
    }
}
